<?php

declare(strict_types=1);

/**
 * @Author:     Frank
 * @contact     frank_hhm@163.com
 * @Date:       2022-12-28 11:31:01
 * @Last Modified time: 2023-02-23 11:40:17
 */
namespace app\common\services\store;

use app\common\dao\store\GoodsDao;

use frank\base\BaseService;
use frank\exception\CommonException;
use frank\utils\helper\ArrayHelper;
use frank\utils\helper\StringHelper;

use app\common\services\store\GoodsCateService;
use app\common\services\store\GoodsSkuService;
use app\common\services\store\GoodsSpecService;
use frank\services\CacheService;
use think\facade\Db;


/**
 * Class GoodsService
 * 缓存 redis
 */
class GoodsService extends BaseService
{
    public $cacheKey = "store:goods:";

    public $cache;

    /**
     * GoodsService constructor.
     * @param GoodsDao $dao
     */
    public function __construct(GoodsDao $dao)
    {
        $this->dao = $dao;
        $this->cache = CacheService::instance()->setHandler('store:goods');
    }


    public function getGoodsFormDetail($goodsId)
    {
        $detail = $this->dao->search(['id'=>$goodsId])->with(['cate','sku','label','server'])->find();
        if (!$detail) {
            throw new CommonException('数据不存在');
        }
        $spec = [
            'names'=>[],
            'attrs'=>[]
        ];
        $specData = [];
        if($detail['spec_type']['value'] == 2){
            $specData = GoodsSpecService::instance()->getGoodsSpecData($detail['id']);
            $spec = GoodsSkuService::instance()->attrFormat($specData);
            foreach ( $detail['sku'] as $key => &$item) {
                $skuAttr = explode(':',$item['sku_attr']);
                $specValueSku = ArrayHelper::getArray2Column($specData,'value');
                foreach ( $skuAttr as $k => $v) {
                    $specValueItem = ArrayHelper::getArrayItemByColumn($specValueSku,'id',$v);
                    if(!empty($specValueItem)){ 
                        $item['attr'.$k] = [
                            'img'=>$specValueItem['img'],
                            'name'=>$specValueItem['name']
                        ];
                    }
                }
            }
        }
        return ['detail'=>$detail->toArray(),'spec'=>$specData,'spec_attr'=>$spec];
    }

    /**
     * 获取列表
     */
    public function getGoodsList(array $params)
    {
        [$page, $limit] = $this->getPageValue();
        $where = $this->getParamWhere($params);
        if(isset($params['destroy'])){
            $where['destroy'] = 1;
        }
        $list = $this->dao->getGoodsList($where,$page, $limit,[],['cate','sku'])->toArray();
        return $list;
    }

    /**
     * 获取列表
     */
    public function getGoodsSimpleList(array $params)
    {
        [$page, $limit] = $this->getPageValue();
        $where = $this->getParamWhere($params);
        $list = $this->dao->getGoodsListAsWith($where,$page, $limit,['id','goods_name','goods_imgs','sales_initial','sales_actual','spec_type'])->toArray();
        return $list;
    }

    /**
     * 添加商品
     */
    public function createGoods(array $data,array $spec = []){
    	$skuService = GoodsSkuService::instance();
    	 // 保存数据
        return $this->transaction(function () use ($data,$spec,$skuService) {
        	$res = $this->dao->create($data);
        	if (!$res) throw new CommonException('保存失败');
            $id = (int)$res->id;
        	$cateList = [];
        	foreach ($data['cate_id'] as $key => $item) {
        		$cateList[] = [
        			'cate_id' => $item
        		];
        	}
        	$labelList = [];
        	foreach ($data['goods_label'] as $key => $item) {
        		$labelList[] = [
        			'label_id' => $item
        		];
        	}
            $serverList = [];
            foreach ($data['goods_server'] as $key => $item) {
                $serverList[] = [
                    'server_id' => $item,
                    'goods_id' => $goodsId
                ];
            }
        	$skuService->saveSku($spec,(int)$data['spec_type'],$id);
	        $res->cateRel()->saveAll($cateList);
	        $res->labelRel()->saveAll($labelList);
            $res->serverRel()->saveAll($serverList);
	        return true;
        });
    }

    /**
     * 修改商品
     */
    public function updateGoods(int $goodsId,array $data,array $spec){
        $skuService = GoodsSkuService::instance();
         // 保存数据
        $status = $this->transaction(function () use ($goodsId,$data,$spec,$skuService) {
            $res = $this->dao->update($goodsId,$data);
            if (!$res) throw new CommonException('保存失败');

            Db::name('store_goods_cate_rel')->where('goods_id',$goodsId)->delete();
            Db::name('store_goods_label_rel')->where('goods_id',$goodsId)->delete();
            Db::name('store_goods_server_rel')->where('goods_id',$goodsId)->delete();

            $cateList = [];
            foreach ($data['cate_id'] as $key => $item) {
                $cateList[] = [
                    'cate_id' => $item,
                    'goods_id' => $goodsId
                ];
            }
            $labelList = [];
            foreach ($data['goods_label'] as $key => $item) {
                $labelList[] = [
                    'label_id' => $item,
                    'goods_id' => $goodsId
                ];
            }
            $serverList = [];
            foreach ($data['goods_server'] as $key => $item) {
                $serverList[] = [
                    'server_id' => $item,
                    'goods_id' => $goodsId
                ];
            }
            $skuService->saveSku($spec,(int)$data['spec_type'],$goodsId);
            $res->cateRel()->saveAll($cateList);
            $res->labelRel()->saveAll($labelList);
            $res->serverRel()->saveAll($serverList);
            return true;
        });
        $this->deleteCache($goodsId);
        return $status;
    }

    /**
     * 删除商品 (真实删除)
     */
    public function deleteGoods($goodsId){
        $skuService = GoodsSkuService::instance();
        return $this->transaction(function () use ($goodsId,$skuService) {
            $goods = $this->dao->get(['id'=>$goodsId],['*'],['cateRel','labelRel'],true);
            if (!$goods) throw new CommonException('商品不存在');
            $res = $goods->together(['cateRel','labelRel'])->force()->delete();
            if (!$res) throw new CommonException('删除失败');
            $skuService->deleteSku($goodsId);
            return true;
        });
    }

    /**
     * 获取商品最小价格规格
     */
    public function getListsPrice(&$data, $isMultiple = true){
        if (!$isMultiple) $dataSource = [&$data]; else $dataSource = &$data;
        foreach ($dataSource as &$goods){
            $skus = is_object($goods['sku']) ? $goods['sku']->toArray() : $goods['sku'];
            $sku = ArrayHelper::getArrayMinItem($skus,'price');
            $goods['goods_price'] = $sku['price'] ?? '0.00';
            $goods['market_price'] = $sku['market_price'] ?? '0.00';
            $goods['stock'] = ArrayHelper::getArrayColumnSum($skus,'stock');
            unset($goods['sku']);
        }
        return $data;
    }

    /**
     * 检测商品信息
     */
    public function checkGoods($detail){
        if (!$detail) {
            throw new CommonException('商品不存在');
        }
        // 判断商品的状态
        if (!empty($detail['goods_status']) && !$detail['goods_status']['value']) {
            throw new CommonException('很抱歉，商品已下架');
        }
        return true;
    }

    /**
     * 指定的商品规格信息
     */
    public function getGoodsSkuItem($goods, $SkuId)
    {
        $goodsSku = [];
        foreach ($goods['sku'] as $item) {
            if ($item['id'] == $SkuId) {
                $goodsSku = $item;
                break;
            }
        }
        if (empty($goodsSku)) {
            return false;
        }
        return $goodsSku;
    }

    /**
     * 处理商品筛选条件
     */
    public function getParamWhere($param = []){
        $filter = [];
        if(!empty($param['cate_id'])){
            $filter['cate_id'] =GoodsCateService::instance()->getIdsByPid((int)$param['cate_id']);
        }
        if(isset($param['goods_name']) && !empty($param['goods_name'])){
            $filter['goods_name'] = $param['goods_name'];
        }
        return $filter;
    }

    /**
     * 商品详细缓存
     */
    public function getCacheDetail($goodsId){


        $cacheDetail = $this->cache->getTokenBucket($this->cacheKey.$goodsId);

        if( !$cacheDetail){
            $filter['id'] = $goodsId;
            // 获取商品详情
            $detail = $this->dao->search($filter)->with(['cate','sku','label','server'])->find();
            $this->checkGoods($detail);

            $cacheDetail =  $this->getListsPrice($detail,false)->toArray();

            $this->cache->setTokenBucket($this->cacheKey.$goodsId,$cacheDetail);
        }
        return $cacheDetail;
    }

    /**
     * 删除商品详细缓存
     */
    public function deleteCache($goodsId = 0){
        if(!$goodsId){
            $this->cache->clear();
        }else{
            $this->cache->clearToken($this->cacheKey.$goodsId);
        }
    }

    
    /**
     * 检测订单商品并返回
     */
    public function checkOrderGoods($goodsList)
    {
        // 商品列表
        foreach ($goodsList as &$item) {
            // 判断商品是否已下架
            if (!$item['goods_status']['value']) {
                $this->setError('商品['.$item['goods_name'].']已下架');
                return false;
            }

            // 商品sku信息
            $item['goods_sku'] = $this->getGoodsSkuItem($item, $item['goods_sku_id']);

            // 商品sku
            if (empty($item['goods_sku'])) {
                $this->setError('商品['.$item['goods_name'].'],规格不存在');
                return false;
            }
            // 商品单价
            $item['goods_price'] = $item['goods_sku']['price'];

            // 商品购买数量
            $item['total_num'] = $item['goods_num'];

            // 库存
            $item['stock'] = $item['goods_sku']['stock'];
            
            $item['sku_attr'] = $item['goods_sku']['sku_attr'];
            // 商品购买总金额
            $item['total_price'] = StringHelper::bcmul($item['goods_price'], $item['total_num']);
        }
        return $goodsList;
    }



    /**
     * 获取状态商品数量
     */
    public function getGoodsStatusCount($status){
        return number_format($this->dao->search(['goods_status'=>$status])->count());
    }
}
